/**
 * com.chaeron.GPS - An API for access to GPS devices.
*
*
* Copyright (c) 2001, 2002 Chaeron Corporation,
* All rights reserved.
* 
* Chaeron grants you a non-exclusive license to use, modify and re-distribute
* this program under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version, provided that this copyright notice and 
* license appear on all copies of the software.
* 
* Software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR
* IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
* HEREBY EXCLUDED. THE ENTIRE RISK ARISING OUT OF USING THE SOFTWARE IS ASSUMED
* BY THE LICENSEE. See the GNU General Public License for more details.
*
* CHAERON AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
* LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR DISTRIBUTING SOFTWARE.
* IN NO EVENT WILL CHAERON OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE,
* PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL
* OR PUNITIVE DAMAGES, HOWEVER CAUSED AN REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF CHAERON HAS
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

* @version     1.02
* @author      Andrzej Jan Taramina, Chaeron Corporation
*              andrzej@chaeron.com
*/

package com.chaeron.GPS.Garmin;

//***************************************************************************
//*
//*     Imports
//*
//***************************************************************************/

import com.chaeron.GPS.*;
import com.chaeron.GPS.event.*;
import com.chaeron.GPS.exception.*;


//***************************************************************************
//*
//*     RecordsGarminPacket Class definition
//*
//***************************************************************************/

/**
 * The PVTGarminPacket class represents PVT Packets
*
*/

public class PVTGarminPacket extends GarminPacket implements GPSPosition, GPSTime, GPSVelocity
{
	//***************************************************************************
	//*
	//*     Constant definitions
	//*
	//***************************************************************************/
	
	//***************************************************************************
	//*
	//*     Attributes
	//*
	//***************************************************************************/
	
	private float		altitude					= 0.0f;
	private float		epe							= 0.0f;
	private float		eph							= 0.0f;
	private float		epv							= 0.0f;
	private short		fix							= 0;
	private double		tow							= 0.0f;
	private double		latRadians					= 0.0f;
	private double		longRadians					= 0.0f;
	private float		east						= 0.0f;
	private float		north						= 0.0f;
	private float		up							= 0.0f;
	private float		mslHeight					= 0.0f;
	private short		leapSeconds					= 0;
	private int			wnDays						= 0;
	
	
	//***************************************************************************
	//*
	//*     Constructors
	//*
	//***************************************************************************/
	
	/**
	 * Create a RecordsGarminPacket from the given packet data
	*
	* @param	packet		packet data buffer
	* @param	len			length of packet data
	*/
	
	PVTGarminPacket( byte[] packet, int len )
	{  
		super( packet, len );
	}
	
	
	//***************************************************************************
	//*
	//*     decode method
	//*
	//***************************************************************************/
	
	/**
	 * Decode the data fields.
	*
	* @throws GPSPacketException
	* @throws GPSFunctionUnavailableException
	*/
	
	public void parseData() throws GPSPacketException, GPSFunctionUnavailableException
	{  
		if( getPacketIDByte() != Protocol.GARMIN_PID_L001_PVT ) {
			throw( new GPSPacketException( GPSPacketException.EXCEPTION_PACKETID_INVALID ) );
		} else if( getDataLength() != 64 ) {
			throw( new GPSPacketException( GPSPacketException.EXCEPTION_PACKETLENGTH_INVALID ) );
		} else {
			altitude 	= getGarminFloat( 0 );
			epe 		= getGarminFloat( 4 );
			eph 		= getGarminFloat( 8 );
			epv 		= getGarminFloat( 12 );
			fix 		= getGarminInt( 16 );
			tow			= getGarminDouble( 18 );
			latRadians	= getGarminDouble( 26 );
			longRadians	= getGarminDouble( 34 );
			east	 	= getGarminFloat( 42 );
			north	 	= getGarminFloat( 46 );
			up		 	= getGarminFloat( 50 );
			mslHeight 	= getGarminFloat( 54 );
			leapSeconds = getGarminInt( 58 );
			wnDays		= getGarminLong( 60 );
		}
	}
	
	
	//***************************************************************************
	//*
	//*     Packet Processing Methods
	//*
	//***************************************************************************/
	
	/**
	 * Process the packet
	*
	* @param	gps			the GPS object that requested the packet to be processed
	*/
	
	void process( GPS gps )
	{
		if( !isParsed() ) {
			try {
				parse();
				gps.postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_POSITION, this ) );
				
				if( fix != GPSPosition.GPSPOSITION_FIX_UNUSEABLE && fix != GPSPosition.GPSPOSITION_FIX_INVALID ) {
					gps.postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_VELOCITY, this ) );
					gps.postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_TIME, this ) );
				}
			}
			catch( GPSException exception ) {
				gps.postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_ERROR, toString(), exception ) );
			}
		}
	}
	
	
	/**
	 * Get events generated.
	*
	* @return		return a valid event type(s) that will be generated by this packet
	*/
	
	static int getEventsGenerated()
	{  
		return( GPSEvent.GPS_EVENT_ERROR | GPSEvent.GPS_EVENT_POSITION | GPSEvent.GPS_EVENT_VELOCITY | GPSEvent.GPS_EVENT_TIME );
	}
	
	
	//***************************************************************************
	//*
	//*    Accessor methods
	//*
	//***************************************************************************/
	
	/**
	 * Get the Altitude above WGS84 (meters)
	*
	* @return		Altitude
	*/
	
	public float getAltitude()
	{  
		return( altitude );
	}
	
	
	/**
	 * Get the Estimated Position Error (meters)
	*
	* @return		Estimated Position Error (meters)
	*/
	
	public float getEPE()
	{  
		return( epe );
	}
	
	
	/**
	 * Get the Estimated Position Error, horizontal only (meters)
	*
	* @return		Estimated Position Error, horizontal only (meters)
	*/
	
	public float getEPH()
	{  
		return( eph );
	}
	
	
	/**
	 * Get the Estimated Position Error, vertical only (meters)
	*
	* @return		Estimated Position Error, vertical only (meters)
	*/
	
	public float getEPV()
	{  
		return( epv );
	}
	
	
	/**
	 * Get the type of position fix
	*
	* @return		type of position fix
	*/
	
	public short getFixType()
	{  
		return( fix );
	}
	
	
	/**
	 * Get the time of week (seconds)
	*
	* @return		time of week (seconds)
	*/
	
	public double getTimeOfWeek()
	{  
		return( tow );
	}
	
	
	/**
	 * Get the UTC Time
	*
	* @return		UTC Time
	*/
	
	public float getUTC()
	{  
		// NIY
		return( 0.0f );
	}
	
	
	/**
	 * Get the Latitude (radians)
	*
	* @return		Latitude (radians)
	*/
	
	public double getLatitudeRadians()
	{  
		return( latRadians );
	}
	
	
	/**
	 * Get the Latitude (degrees)
	*
	* @return		Latitude (degrees)
	*/
	
	public double getLatitude()
	{  
		return( GPS.convertRadiansToDegrees( latRadians ) );
	}
	
	
	/**
	 * Get the Longitude (radians)
	*
	* @return		Longitude (radians)
	*/
	
	public double getLongitudeRadians()
	{  
		return( longRadians );
	}
	
	
	/**
	 * Get the Longitude (degrees)
	*
	* @return		Longitude (degrees)
	*/
	
	public double getLongitude()
	{  
		return( GPS.convertRadiansToDegrees( longRadians ) );
	}
	
	
	/**
	 * Get the velocity
	*
	* @return		velocity
	*/
	
	public double getVelocity()
	{  
		return( Math.sqrt( east*east + north*north + up*up ) );
	}
	
	
	/**
	 * Get the velocity east
	*
	* @return		velocity east (meters/sec)
	*/
	
	public float getVelocityEast()
	{  
		return( east );
	}
	
	
	/**
	 * Get the velocity north
	*
	* @return		velocity north (meters/sec)
	*/
	
	public float getVelocityNorth()
	{  
		return( north );
	}
	
	
	/**
	 * Get the velocity up
	*
	* @return		velocity up (meters/sec)
	*/
	
	public float getVelocityUp()
	{  
		return( up );
	}
	
	
	/**
	 * Get the height of WGS 84 ellipsoid above MSL (meters)
	*
	* @return		height of WGS 84 ellipsoid above MSL (meters)
	*/
	
	public float getMSLHeight()
	{  
		return( mslHeight );
	}
	
	
	/**
	 * Get the difference between GPS and UTC times (seconds)
	*
	* @return		difference between GPS and UTC times (seconds)
	*/
	
	public short getLeapSeconds()
	{  
		return( leapSeconds );
	}
	
	
	/**
	 * Get the week number days
	*
	* @return		week number days
	*/
	
	public int getWeekNumberDays()
	{  
		return( wnDays );
	}
}
